using System;
using System.Collections.Generic;
using System.Text;
using Microformats.Interfaces;

namespace Microformats.Entities
{
    public abstract class BaseField :IField 
    {
        protected string name;
        protected string humanValue;
        protected string machineValue;
        protected List<IField> fields;
        protected List<IField> secretFields;
        private IField parentField;


        /// <summary>
        /// A string telling the developer that the name of the current microformat.
        /// </summary>
        /// TODO:  Potentially make the set internal protected, so that only the framework can set the type.
        public string Name
        {
            get
            {
                return name;
            }
            set
            {
                if (value == String.Empty)
                    throw new ArgumentException("Type is not allowed to be blank");
                name = value;
            }
        }

        /// <summary>
        /// A string telling the developer that human readable value that is stored in the microformat.
        /// </summary>
        /// TODO:  Potentially make the set internal protected, so that only the framework can set the type.
        public string HumanValue
        {
            get
            {
                if (string.IsNullOrEmpty(humanValue))
                {
                    //If the machine value is empty itterate accross all the contained fields to determine the combined machine value
                    string combinedHumanValue = "";

                    foreach (IField f in fields)
                    {
                        combinedHumanValue += f.HumanValue;
                    }

                    foreach (IField f in secretFields)
                    {
                        combinedHumanValue += f.HumanValue;
                    }

                    return combinedHumanValue;
                }
                else
                {
                    return humanValue;
                }
            }
            set
            {
                humanValue = value;
            }
        }

        /// <summary>
        /// A string telling the developer that machine readable value that is stored in the microformat.
        /// </summary>
        /// TODO:  Potentially make the set internal protected, so that only the framework can set the type.
        public string MachineValue
        {
            get
            {
                if (string.IsNullOrEmpty(machineValue))
                {
                    //If the machine value is empty itterate accross all the contained fields to determine the combined machine value
                    string combinedMachineValue = "";

                    foreach (IField f in fields)
                    {
                        combinedMachineValue += f.MachineValue;
                    }

                    foreach (IField f in secretFields)
                    {
                        combinedMachineValue += f.HumanValue;
                    }

                    return combinedMachineValue;
                }
                else
                {
                    return machineValue;
                }
            }
            set
            {
                machineValue = value;
            }
        }

        /// <summary>
        /// Secret Fields is populated when the current node has normal elements and child nodes shared.  It should be hidden from all external developers.
        /// </summary>
        internal List<IField> SecretFields { get { return secretFields; } }

        public List<IField> Fields
        {
            get { return fields; }
        }

        /// <summary>
        /// Exists the in collection.
        /// </summary>
        /// <param name="f">The f.</param>
        /// <returns></returns>
        public bool ExistsInCollection(IField f)
        {
            if (Name == f.Name) return true;
            else return false;
        }

        /// <summary>
        /// Finds an instance of a given field by name.
        /// </summary>
        /// <param name="fieldName">The name.</param>
        /// <returns></returns>
        public IField FindFieldByName(string fieldName)
        {
            if (this.name == fieldName)
                return this;

            IField lastField = null;

            foreach (IField field in fields)
            {
                if (field.Name == fieldName)
                {
                    lastField = field;
                }
                else if (field.Fields.Count > 0)
                {
                    foreach (IField nestedFields in field.Fields)
                    {
                        IField currentField = nestedFields.FindFieldByName(fieldName);
                        if(currentField != null)
                        {
                            lastField = currentField;
                        }
                    }
                }
            }
            return lastField;
        }

    }
}
